package com.free.ext.shiro.filter;

import com.free.ext.logger.FreeLogger;
import com.free.ext.logger.FreeLoggerFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 功能概述:
 * </p>
 * <p>
 * 功能详述:
 * </p>
 */
public abstract class CustomAuthenticationFilter extends CaptchaFormAuthenticationFilter {
    /*========================================================================*
     *                         Public Fields (公共属性)
     *========================================================================*/

    /*========================================================================*
     *                         Private Fields (私有属性)
     *========================================================================*/

    private static FreeLogger LOGGER = FreeLoggerFactory.getLogger(CustomAuthenticationFilter.class);

    private static final String PAGE_SUFFIX = "jhtml";

    private static final String AJAX_SUFFIX = "ahtml";

    private static final String TOKEN_USERNAME = "username";

    private List<String> loginUrls = new ArrayList<>();

    private String pageSuffix = PAGE_SUFFIX;

    private String ajaxSuffix = AJAX_SUFFIX;

    /*========================================================================*
     *                         Construct Methods (构造方法)
     *========================================================================*/

    /*========================================================================*
     *                         Public Methods (公有方法)
     *========================================================================*/

    @Override
    public boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
                                  ServletResponse response) throws Exception {

        loginSuccess(subject.getPrincipal());

        if(isRestfulRequest(request)){
            return true;
        }

        return super.onLoginSuccess(token, subject, request, response);
    }

    @Override
    public boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request,
                                  ServletResponse response) {
        LOGGER.info("登录失败[{}][{}][{}]", token.getPrincipal(), e.getClass().getName(), e.getMessage());

        if (e instanceof IncorrectCredentialsException){
            String userName = WebUtils.toHttp(request).getParameter(TOKEN_USERNAME);
            loginFailure(userName);
        }

        return super.onLoginFailure(token, e, request, response);
    }

    @Override
    public void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        if(isRestfulRequest(request)){
            WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        super.saveRequestAndRedirectToLogin(request, response);
    }

    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if(isLoginRequest(request, response)){
            return false;
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }

    /**
     * 判断是否为登录请求
     */
    @Override
    protected boolean isLoginRequest(ServletRequest request, ServletResponse response) {
        boolean flg = false;
        for(String pattern : loginUrls){
            if(pathsMatch(pattern,request)){
                flg = true;
                break;
            }
        }
        return flg;
    }

    public void setLoginurls(String custLoginUrls){
        String[] custSpliteds = StringUtils.split(custLoginUrls,",");
        if(custSpliteds == null || custSpliteds.length == 0){
            return;
        }
        for(String custSplit : custSpliteds){
            loginUrls.add(custSplit);
        }
    }

    public String getPageSuffix() {
        return pageSuffix;
    }

    public void setPageSuffix(String pageSuffix) {
        this.pageSuffix = pageSuffix;
    }

    public String getAjaxSuffix() {
        return ajaxSuffix;
    }

    public void setAjaxSuffix(String ajaxSuffix) {
        this.ajaxSuffix = ajaxSuffix;
    }

    public abstract void loginSuccess(Object object);

    public abstract void loginFailure(String custName);
    /*========================================================================*
     *                         Private Methods (私有方法)
     *========================================================================*/

    /**
     * 判断是否为AJAX 请求
     * @param request
     * @return
     */
    private boolean isRestfulRequest(ServletRequest request){

        // 获取请求方式
        String requestType = WebUtils.toHttp(request).getHeader("X-Requested-With");

        // 是 ajax 请求的场合，当作 rest api 调用处理
        // 不是 jhtml 请求的场合，当作 rest api 调用处理
        return "XMLHttpRequest".equals(requestType) ||
                WebUtils.toHttp(request).getRequestURI().toLowerCase().endsWith(ajaxSuffix);
    }


}
